#include "helper/sqlite/shortcut/QueryScalar.h"

#include "helper/sqlite/IDB.h"
#include "helper/sqlite/Statement.h"
#include "helper/sqlite/QueryResult.h"

#include "helper/sqlite/shortcut/Query.h"



namespace helper {
namespace sqlite {
namespace shortcut {


template<typename T>
void __assignFromValue(T & v, Value & value){
  v = T();
}
template<>
void __assignFromValue<int>(int & v, Value & value){
  v = value.integer();
}
template<>
void __assignFromValue<double>(double & v, Value & value){
  v = value.real();
}

template<>
void __assignFromValue<std::string>(std::string & v, Value & value){
  v = value.string();
}

template<typename T>
static std::error_code fetch(QueryResult & result, T & v){
    auto && value = result.values(0);
    if(value && result.columnCount() >= 1){
      __assignFromValue<T>(v, value.value());
      return std::error_code();
    }
    return std::make_error_code(std::errc::invalid_argument);//fetch empty table
}

QueryScalar::QueryScalar(IDB & db)
: _query( new Query(db))
{
}
QueryScalar::~QueryScalar(){
  if(_query != nullptr){
    delete _query;
    _query = nullptr;
  }
}

std::error_code QueryScalar::queryInteger(const std::string & sql, int & v, const fbind_type & fbind) const{
  return _query->query(sql, std::bind(fetch<int>, std::placeholders::_1, std::ref(v)), fbind);
}

std::error_code QueryScalar::queryReal(const std::string & sql, double & v, const fbind_type & fbind) const{
  return _query->query(sql, std::bind(fetch<double>, std::placeholders::_1, std::ref(v)), fbind);
}
std::error_code QueryScalar::queryText(const std::string & sql, std::string & v, const fbind_type & fbind) const {
  return _query->query(sql, std::bind(fetch<std::string>, std::placeholders::_1, std::ref(v)), fbind);
}


std::error_code QueryScalar::queryBinary(const std::string & sql, std::string & v, const fbind_type & fbind) const {
  auto && fetch = [&v](QueryResult & result){
    auto && value = result.values(0);
    if(value && result.columnCount() >= 1){
      v = value->binary();
      return std::error_code();
    };
    return std::make_error_code(std::errc::invalid_argument);//fetch empty table
  };
  return _query->query(sql, fetch, fbind);
}


}//namespace shortcut
}//namespace sqlite
}//namespace helper
